package com.seari.shiro;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.seari.pojo.MessageBean;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import java.io.IOException;
import java.io.PrintWriter;

public class JwtFilter extends AccessControlFilter {

    private static final Logger LOG = LoggerFactory.getLogger(JwtFilter.class);

    public static final String AUTHORIZATION = "Authorization";

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o){
        if (null != getSubject(servletRequest, servletResponse)
                && getSubject(servletRequest, servletResponse).isAuthenticated()) {
            return true;
        }
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception{
    	MessageBean messageBean = new MessageBean();
    	if(isJwtSubmission(servletRequest)){
            AuthenticationToken token = createToken(servletRequest, servletResponse);
            try{
                Subject subject = getSubject(servletRequest, servletResponse);
                subject.login(token);
                return true;
            }catch (ExpiredCredentialsException e) {
                //WebUtils.toHttp(servletResponse).sendRedirect("../api/expiredCredentials");
            	messageBean.setCode("401");
            	messageBean.setMessage("expiredCredentials");
            	writeJson(messageBean,servletResponse);
            } catch (UnknownAccountException e) {
                //WebUtils.toHttp(servletResponse).sendRedirect("../api/unknownAccount");
            	messageBean.setCode("401");
            	messageBean.setMessage("unknownAccount");
            	writeJson(messageBean,servletResponse);
            } catch (IncorrectCredentialsException e) {
                //WebUtils.toHttp(servletResponse).sendRedirect("../api/incorrectCredentials");
                messageBean.setCode("401");
            	messageBean.setMessage("incorrectCredentials");
            	writeJson(messageBean,servletResponse);
            } catch (UnsupportedTokenException e) {
                //WebUtils.toHttp(servletResponse).sendRedirect("../api/unsupportedToken");
            	messageBean.setCode("401");
            	messageBean.setMessage("unsupportedToken");
            	writeJson(messageBean,servletResponse);
            } catch (Exception e) {
                //WebUtils.toHttp(servletResponse).sendRedirect("../api/authentication");
            	messageBean.setCode("401");
            	messageBean.setMessage("authentication");
            	writeJson(messageBean,servletResponse);
            }
        }else{
            //WebUtils.toHttp(servletResponse).sendRedirect("../api/unauthorized");
        	messageBean.setCode("401");
        	messageBean.setMessage("unauthorized");
        	writeJson(messageBean,servletResponse);
        }
        return false;
    }

    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String jwt = httpServletRequest.getHeader(AUTHORIZATION);
        String host = httpServletRequest.getRemoteHost();
        LOG.info("authenticate jwt token:"+jwt);
        return new JwtToken(jwt, host);
    }

    protected boolean isJwtSubmission(ServletRequest request) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String jwt = httpServletRequest.getHeader(AUTHORIZATION);
        return (request instanceof HttpServletRequest)
                && !StringUtils.isEmpty(jwt);
    }
    
    /**
     * 
     * @param messageBean
     * @param response
     */
    private void writeJson(MessageBean messageBean, ServletResponse response) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            out = response.getWriter();
            ObjectMapper mapper = new ObjectMapper();
            out.write(mapper.writeValueAsString(messageBean));
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

}